package com.xnx3.weixin.weixinPay.v2;
import java.io.IOException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.xnx3.BaseVO;
import com.xnx3.Log;
import com.xnx3.weixin.SignUtil;
import com.xnx3.weixin.XmlUtil;
import com.xnx3.weixin.weixinPay.PayCallBackParamsVO;

/**
 * JSAPIPay、NativePay、AppPay 等支付的父类
 * @author 管雷鸣
 */
public class Pay {
	public static String UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
	
	/**
	 * 微信支付的商户号，格式如：1581125900 ，登录 https://pay.weixin.qq.com/ 取得
	 */
	public String mch_id = "";
	/**
	 * 微信支付的API密钥，32位字符串。登录 https://pay.weixin.qq.com/  在 [账户中心] - [API安全] - [设置API密钥]
	 */
	public String mch_key = "";
	
	/**
	 * 微信公众号的appid，格式如 wx07f3db3a6bbexxxx
	 */
	public String gongzhonghao_appid = "";
	/**
	 * 微信公众号的 appsecret ，格式如 b067bdd3935962ff8262f51fe5054xxx
	 */
	public String gongzhonghao_appsecret = "";
	
	/**
	 * 微信支付成功后，微信服务器会将支付结果异步通知我们的服务器。这里是异步通知的url。传入如 http://xxx.zvo.cn/weixin.do
	 * 异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数。 公网域名必须为https，如果是走专线接入，使用专线NAT IP或者私有回调域名可使用http
	 */
	public String notify_url = "";	//支付成功的通知地址
	
	/**
	 * 支付类型
	 * JSAPI -JSAPI支付
	 * NATIVE -Native支付
	 * APP -APP支付
	 */
	String trade_type = "JSAPI"; 
	
	/**
	 * 微信支付成功的回调，自动验证签名，并检查是不是支付成功的回调，拿到支付成功通知的订单号no
	 * @return <ul>
	 * 				<li>result=BaseVO.SUCCESS 是支付成功，可以用 getInfo() 拿到支付成功的订单号，也就是createPayOrder方法中传入的no订单号</li>
	 * 				<li>result=BaseVO.FAILURE 失败，异常，理论上应该不会这样，开发阶段会碰到，可以直接通过 info 来看失败原因</li>
	 * 			</ul>
	 */
	public PayCallBackParamsVO callback(HttpServletRequest request){
		PayCallBackParamsVO vo = new PayCallBackParamsVO();
		
        String inputLine = "";
        String notityXml = "";
        try {
			while((inputLine = request.getReader().readLine()) != null){
			    notityXml += inputLine;
			}
			//关闭流
            request.getReader().close();
            Log.debug("微信回调内容信息："+notityXml+"  可设置 com.xnx3.Log.debug = false; 关闭信息打印");
		} catch (IOException e) {
			e.printStackTrace();
		}
        if(notityXml.length() > 0){
        	//有信息
        	
        	Map<String,String> map;
        	try {
				map = XmlUtil.stringToMap(notityXml);
			} catch (Exception e) {
				e.printStackTrace();
				vo.setBaseVO(BaseVO.FAILURE, e.getMessage());
				return vo;
			}
        	String no = map.get("out_trade_no");	//取到订单号
        	if(no == null){
        		vo.setBaseVO(BaseVO.FAILURE, "out_trade_no not find");
				return vo;
        	}
        	
    		//回调验签、以及看其是否是支付成功
            if(map.get("result_code") != null && "SUCCESS".equals(map.get("result_code"))){
            	/*
            	 * 签名校验
            	 */
            	String signStr = map.get("sign");
            	map.remove("sign");
            	
//            	//调用逻辑传入参数按照字段名的 ASCII 码从小到大排序（字典序）
//                String stringA = formatUrlMap(map, false, false);
//                //第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，得到sign值signValue。(签名)
//                String nSign = MD5Util.MD5(stringA+"&key="+shanghu_key).toUpperCase();
                String sign = SignUtil.generateSign(map, this.mch_key);
                Log.debug("sign:  "+sign+", param Sign:"+signStr);
            	if(sign.equalsIgnoreCase(signStr)){
            		//成功
            		
            		Log.debug("微信回调返回是否支付成功：是");
            		vo.setParams(map);
            		//通知微信服务器，已经成功处理，这个数据不要在请求了
            		vo.setInfo("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
                	vo.setResult(BaseVO.SUCCESS);
            		return vo;
            	}else{
            		//签名对比出错，警报！可能有人利用接口攻击了
//            		debug("签名对比出错，警报！可能有人利用接口攻击了-->"+map.toString());
            		vo.setBaseVO(BaseVO.FAILURE, "签名对比出错");
            		return vo;
            	}
            }else{
            	vo.setBaseVO(BaseVO.FAILURE, notityXml);
            	return vo;
            }
        }
        
        vo.setBaseVO(BaseVO.FAILURE, "failure");
		return vo;
	}

	/**
	 * 支付回调中，通知微信服务器，执行成功，不要再给我发这个订单支付成功的消息了
	 * @return <pre>
	 * 				<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>
	 *			</pre>
	 */
	public static String callbackExecuteSuccess() {
		return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
	}
}
